home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 76 / XENIATGM66.iso / Indiana Jones / Indiana Jones.exe / RESOURCE / PREVIEW.GOB / cog_aet_aimophia.cog < prev    next >
Text File  |  1999-11-15  |  21KB  |  786 lines

  1. # Jones 3D Cog Script
  2. #
  3. # AET_AIMophia.cog
  4. #
  5. # AI enhancements for AET Mophia Boss
  6. #
  7. # [MDR]
  8. #
  9. # (C) 1999 LucasArts Entertainment Company LLC. All Rights Reserved
  10. #
  11. #    #####  COG Notes  #####
  12. #    The following functionality can be accessed with USER msgs sent to this COG
  13. #
  14. #    USER0 - Create Mophia.                    param0 = Ghost THING used as position to be created at.
  15. #    USER1 - Put Mophia "into play."
  16. #    USER2 - Transform Mophia to next "smaller version."
  17. #    USER3 - Reset Mophia to a neutral state.
  18. #
  19. #
  20. # ===================================================================
  21.  
  22. # ===================================================================
  23. symbols
  24.  
  25.     message        user0
  26.     message        user1
  27.     message        user2
  28.     message        user3
  29.     message        entered
  30.     message        exited
  31.     message        damaged
  32.     message        timer
  33.     message        pulse
  34.     message        startup
  35.     message        aievent
  36.     message        arrivedwpnt
  37.  
  38. # ************************** SUBROUTINES ***********************
  39. flex        BeginRestMode                local
  40. flex        FleeToRestPosition            local
  41. flex        EndRestMode                    local
  42. flex        StartSwoopAttack            local
  43. flex        FinishSwoopAttack            local
  44. flex        TerminateSwoopAttack        local
  45. flex        AbortSwoopAttack            local
  46. flex        PrepForDeath                local
  47.  
  48. # ************************** LINKED ITEMS **********************
  49. thing        t_ghostPos00                            # Mophia home pos
  50. thing        t_ghostPos01                            # Arena center pos
  51. thing        t_ghostPos02                            # Platform 1
  52. thing        t_ghostPos03                            # Platform 2
  53. thing        t_ghostPos04                            # Platform 3
  54. thing        t_ghostPos05                            # Lower Tier wpnt
  55. thing        t_ghostPos06
  56. thing        t_ghostPos07
  57. thing        t_ghostPos08
  58. thing        t_ghostPos09
  59. thing        t_ghostPos10
  60. thing        t_ghostPos11                            # Middle Tier wpnt
  61. thing        t_ghostPos12
  62. thing        t_ghostPos13
  63. thing        t_ghostPos14
  64. thing        t_ghostPos15
  65. thing        t_ghostPos16
  66. thing        t_ghostPos17                            # Upper Tier wpnt
  67. thing        t_ghostPos18
  68. thing        t_ghostPos19
  69. thing        t_ghostPos20
  70. thing        t_ghostPos21
  71. thing        t_ghostPos22
  72. thing        t_ghostPos23
  73. thing        t_ghostPos24
  74. thing        t_ghostPos25
  75.  
  76. thing        plate_0                                    # Invisa plates
  77. thing        plate_1
  78.  
  79. sector        sec_trig00
  80. sector        sec_trig01
  81. sector        sec_trig02
  82. sector        sec_trig03
  83. sector        sec_trig04
  84.  
  85. # ************************** TEMPLATES *************************
  86. template    tpl_Boss=mophia                local
  87. template    tpl_Boss_med=mophia_med        local
  88. template    tpl_Boss_sml=mophia_sml        local
  89. template    tpl_Boss_xsml=mophia_xsml    local
  90.  
  91. # ************************** AI VARS ***************************
  92. cog            cog_cinematic                local                # ref to COG who called us
  93.  
  94. int            n_AICstmMode                local
  95. int            CMODE_SUFFERING=1            local
  96. int            CMODE_NEEDREST=2            local
  97. int            CMODE_BOMBATTACK=4            local
  98. int            CMODE_SWOOPATTACK=8            local
  99. int            CMODE_PERCH=16                local
  100. int            CMODE_HEAL=32                local
  101. int            CMODE_NORANGED=64            local
  102. int            CMODE_SWOOPFLIGHT=128        local
  103.  
  104. int            n_minPulse                    local
  105. int            n_activeLayer                local
  106. int            n_maxPulse                    local
  107.  
  108. int            b_rangedAttack                local
  109. int            n_totalShots                local
  110. int            n_maxShots                    local
  111.  
  112. int            TIMERID_REST=1                local
  113. int            TIMERID_SWOOP=2                local
  114. int            TIMERID_ABORTSWOOP=3        local
  115.  
  116. flex        f_restTime                    local
  117. flex        f_moveSize                    local
  118. flex        f_dist                        local
  119. int            num_WhipHits                local
  120. int            num_WhipDeath                local
  121.  
  122. # ************************** MISC LOCAL VARS *******************
  123. thing        t_boss                        local
  124. thing        t_player                    local
  125. sector        sec_boss                    local
  126.  
  127. int            n_MophiaSize                local
  128. int            snd_screech                    local
  129.  
  130. int            n_ID                        local
  131. int            n_eventType                    local
  132. int            n_param                        local
  133. int            n_touchCount                local
  134.  
  135. int            n_crntWpnt                    local
  136. int            n_nextWpnt                    local
  137. int            n_countWpnt=-1                local
  138.  
  139. flex        f_val                        local
  140. vector        vec_dir                        local
  141. vector        vec_pos                        local
  142.  
  143. end
  144.  
  145.  
  146. # ===================================================================
  147. code
  148.  
  149. # ...................................................................
  150. startup:
  151.  
  152.     t_boss = -1;
  153.  
  154.     return;
  155.  
  156.  
  157. # ...................................................................
  158. # Create Mophia at location-THING == GetParam(0)                [must be a valid GHOST THING]
  159. user0:
  160.  
  161.     cog_cinematic        = GetSenderRef();                        # Remember who called us
  162.     t_player            = GetLocalPlayerThing();                # Set constants
  163.  
  164.     t_boss                = CreateThing(tpl_Boss, GetParam(0));
  165.  
  166.     CaptureThing(t_boss);
  167.     AISetInstinctWpntMode(t_boss);
  168.     PlaySoundClass(t_boss, 123);                                # play loop sound
  169.  
  170.     ClearActorFlags(t_boss, 0x80000);
  171.     AISetCutsceneMode(t_boss);                                    # Put Boss into cutscene mode until further notice
  172.  
  173.     ReturnEx(t_boss);                                            # return Boss THING index to caller
  174.  
  175.     return;
  176.  
  177.  
  178. # ...................................................................
  179. # Put Mophia into play
  180. user1:
  181.  
  182. #    DEBUGPRINT("aet_AIMophia:: Mophia in play");
  183.     AIClearCutsceneMode(t_boss);
  184.  
  185.     #***  Get current Mophia size (USER4)  ***#
  186.     n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  187.  
  188.     for ( n_param = 0; n_param < 23; n_param = n_param + 1 )
  189.     {
  190.         AISetWpnt(t_ghostPos00[n_param], n_param);
  191.     }
  192.  
  193.     AIConnectWpnts(1, 2);                            #---- Platform combat wpnts
  194.     AIConnectWpnts(1, 3);
  195.     AIConnectWpnts(1, 4);
  196.     for ( n_param = 1; n_param <= 4; n_param = n_param + 1 )
  197.     {
  198.         AISetWpntFlags(n_param, 0x2000);            # Set AIWPNT_LAYER1
  199.     }
  200.  
  201.     AIConnectWpnts(5, 6);                            #---- Outer floor wpnts
  202.     AIConnectWpnts(6, 7);
  203.     AIConnectWpnts(7, 8);
  204.     AIConnectWpnts(8, 9);
  205.     AIConnectWpnts(9, 10);
  206.     AIConnectWpnts(10, 5);
  207.     for ( n_param = 5; n_param <= 10; n_param = n_param + 1 )
  208.     {
  209.         AISetWpntFlags(n_param, 0x10000);            # Set AIWPNT_LAYER4
  210.         AISetWpntFlags(n_param, 0x20000);            # Set AIWPNT_LAYER5
  211.     }
  212.  
  213.     AIConnectWpnts(11, 12);                            #---- Inner floor wpnts
  214.     AIConnectWpnts(12, 13);
  215.     AIConnectWpnts(13, 14);
  216.     AIConnectWpnts(14, 15);
  217.     AIConnectWpnts(15, 16);
  218.     AIConnectWpnts(16, 11);
  219.     for ( n_param = 11; n_param <= 16; n_param = n_param + 1 )
  220.     {
  221.         AISetWpntFlags(n_param, 0x8000);            # Set AIWPNT_LAYER3
  222.         AISetWpntFlags(n_param, 0x20000);            # Set AIWPNT_LAYER5
  223.     }
  224.  
  225.     AIConnectWpnts(10, 15);                            # Connect inner and outer floor wpnts
  226.  
  227.     AIConnectWpnts(17, 18);                            #---- Upper Tier wpnts
  228.     AIConnectWpnts(18, 19);
  229.     AIConnectWpnts(19, 20);
  230.     AIConnectWpnts(20, 21);
  231.     AIConnectWpnts(21, 22);
  232.     AIConnectWpnts(22, 17);
  233.     for ( n_param = 17; n_param <= 22; n_param = n_param + 1 )
  234.     {
  235.         AISetWpntFlags(n_param, 0x4000);            # Set AIWPNT_LAYER2
  236.     }
  237.  
  238.  
  239.     PlaySoundClass(t_boss, 123);                    # play loop sound
  240.  
  241.     num_WhipHits  = 0;
  242.     f_restTime    = 4;
  243.  
  244.     n_minPulse = 3;
  245.     n_maxPulse = 6;
  246.     SetPulse(RandBetween(n_minPulse, n_maxPulse));
  247.  
  248.     if ( n_MophiaSize == 3 )
  249.     {
  250.         n_activeLayer = 0x4000;                        # Initial patrol route is upper tier
  251.         AISetActiveWpntLayer(n_activeLayer);
  252.  
  253.         #***  Start boss resting initially  ***#
  254.         call BeginRestMode;
  255.     }
  256.     else
  257.     {
  258.         n_activeLayer = 0x8000;                        # Standard patrol route is inner floor area
  259.         AISetActiveWpntLayer(n_activeLayer);
  260.  
  261.         #***  Otherwise, start boss moving  ***#
  262.         n_nextWpnt    = AIFindNearestWpnt(t_boss);
  263.         AITraverseWpnts(t_boss, n_nextWpnt, 1.5, 0, 1);
  264.     }
  265.  
  266.     return;
  267.  
  268.  
  269. # ...................................................................
  270. # Transform Mophia
  271. user2:
  272.  
  273.     #***  Get current Mophia size (USER4)  ***#
  274.     n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  275.  
  276.     if ( n_MophiaSize == 0 )
  277.         return;
  278.  
  279.     Reset();
  280.  
  281.     KillTimerEx(TIMERID_REST);                                    # Common reset
  282.     KillTimerEx(TIMERID_SWOOP);
  283.     KillTimerEx(TIMERID_ABORTSWOOP);
  284.     SendMessage(GetThingClassCog(t_boss), USER2);
  285.  
  286.     vec_pos = GetThingPos(t_boss);
  287.     vec_dir = GetThingLVecPYR(t_boss);
  288.     sec_boss= GetThingSector(t_boss);
  289.  
  290.     ReleaseThing(t_boss);
  291.     DestroyThing(t_boss);                                        # Destroy current version
  292.  
  293.     if( n_MophiaSize == 3 )
  294.     {
  295.         t_boss = CreateThingAtPos(tpl_Boss_med, sec_boss, vec_pos, vec_dir);
  296.     }
  297.     else if( n_MophiaSize == 2)
  298.     {
  299.         t_boss = CreateThingAtPos(tpl_Boss_sml, sec_boss, vec_pos, vec_dir);
  300.     }
  301.     else if( n_MophiaSize == 1 )
  302.     {
  303.         t_boss = CreateThingAtPos(tpl_Boss_xsml, sec_boss, vec_pos, vec_dir);
  304.     }
  305.  
  306.     CaptureThing(t_boss);
  307.  
  308.     AISetInstinctWpntMode(t_boss);
  309.     ReturnEx(t_boss);
  310.  
  311.     return;
  312.  
  313.  
  314. # ...................................................................
  315. # Reset Mophia to neutral state
  316. user3:
  317.  
  318.     Reset();
  319.  
  320. # ...................................................................
  321. PrepForDeath:
  322.  
  323.     KillTimerEx(TIMERID_REST);
  324.     KillTimerEx(TIMERID_SWOOP);
  325.     KillTimerEx(TIMERID_ABORTSWOOP);
  326.     SendMessage(GetThingClassCog(t_boss), USER3);                        # Reset VFX and AI to neutral state
  327.  
  328.     AIClearSubMode(t_boss, 0x8000);                                        # Clear SUBMODE_CONTINUOUSWPNTMOTION
  329.     StopThing(t_boss);
  330.  
  331.     SetPulse(0);
  332.  
  333.     return;
  334.  
  335.  
  336. # ...................................................................
  337. entered:
  338.  
  339.     if ( t_boss == -1 )
  340.         return;
  341.  
  342.     if ( GetSourceRef() == t_player )
  343.     {
  344.         #***  Get current Mophia size (USER4)  ***#
  345.         n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  346.  
  347.         #***  Player entered floor area  ***#
  348.         if ( GetSenderRef() == sec_trig00 )
  349.         {
  350. #            DEBUGPRINT("aet_AIMophia:: Indy Entered arena floor sector");
  351.             #***  Enable bomb attack mode  ***#
  352.             SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_BOMBATTACK, 0, 0);
  353.  
  354.             #***  Activate inner floor route (LAYER3), default  ***#
  355.             n_activeLayer = 0x8000;
  356.             AISetActiveWpntLayer(n_activeLayer);                    # Set LAYER3 active
  357.  
  358.             #***  Activate inner floor route (LAYER5), if large  ***#
  359.             if ( n_MophiaSize==3 )
  360.             {
  361.                 n_activeLayer = 0x20000;
  362.                 AISetActiveWpntLayer(n_activeLayer);                # Set LAYER5 active
  363.             }
  364.         }
  365.  
  366.         #***  Player entered combat arena  ***#
  367.         if ( (GetSenderRef() == sec_trig01) )
  368.         {
  369.             f_val = VectorZ( VectorSub(GetThingPos(t_player), GetThingPos(t_ghostPos00)) );
  370.             if ( (f_val < 1.5) || (n_MophiaSize==0) )
  371.             {
  372.                 #***  Activate outer floor route (LAYER4)  ***#
  373. #                DEBUGPRINT("aet_AIMophia:: Indy entered arena sector near combat stage");
  374.                 n_activeLayer = 0x10000;
  375.                 AISetActiveWpntLayer(n_activeLayer);                # Set LAYER4 active
  376.  
  377.                 #***  Set no ranged weapon mode  ***#
  378.                 SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_NORANGED, 0, 0);
  379.             }
  380.             else
  381.             {
  382.                 #***  Activate upper tier route (LAYER2)  ***#
  383. #                DEBUGPRINT("aet_AIMophia:: Indy entered arena sector near upper tier");
  384.                 n_activeLayer = 0x4000;
  385.                 AISetActiveWpntLayer(n_activeLayer);                # Set LAYER2 active
  386.             }
  387.         }
  388.     }
  389.     return;
  390.  
  391.  
  392. # ...................................................................
  393. exited:
  394.  
  395.     if ( t_boss == -1 )
  396.         return;
  397.  
  398.     if ( GetSourceRef() == t_player )
  399.     {
  400.         #***  Get current Mophia size (USER4)  ***#
  401.         n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  402.  
  403.         if ( GetSenderRef() == sec_trig00 )
  404.         {
  405. #            DEBUGPRINT("aet_AIMophia:: Indy Exited arena floor sector");
  406.             #***  Clear bomb attack mode  ***#
  407.             SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_BOMBATTACK, 0, 0);
  408.  
  409.             #***  Clear final combat mode  ***#
  410.             SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_NORANGED, 0, 0);
  411.  
  412.             call FinishSwoopAttack;
  413.  
  414.             #***  Activate inner floor route (LAYER3)  ***#
  415.             n_activeLayer = 0x8000;
  416.             AISetActiveWpntLayer(n_activeLayer);                # Set LAYER3 active
  417.         }
  418.  
  419.         #***  Player exited combat arena  ***#
  420.         if ( (GetSenderRef() == sec_trig01) )
  421.         {
  422. #            DEBUGPRINT("aet_AIMophia:: Indy Exited arena sector");
  423.  
  424.             #***  Clear no ranged weapon mode  ***#
  425.             SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_NORANGED, 0, 0);
  426.         }
  427.     }
  428.     return;
  429.  
  430.  
  431. # ...................................................................
  432. aievent:
  433.  
  434.     if ( GetSenderRef() != t_boss ) return;
  435.  
  436.     #***  Retrieve current custom mode (USER1)  ***#
  437.     n_AICstmMode = SendMessageEx(GetThingClassCog(t_boss), USER1, 0, 0, 0, 0);
  438.  
  439.     n_eventType    = GetParam(0);
  440.     n_param        = GetParam(2);                                # Value depends on n_eventType
  441.  
  442.     if ( n_eventType == 0x04 )                                #---- EVENT_TOUCHED ----
  443.     {                                                        #---- n_param == touched THING index
  444.         ReturnEx(1);
  445.         if ( BITTEST(n_AICstmMode, CMODE_SWOOPATTACK) )
  446.         {
  447.             if (n_param == t_player)
  448.             {
  449.                 call FinishSwoopAttack;
  450.             }
  451.  
  452.             n_touchCount = n_touchCount + 1;
  453.             if ( n_touchCount > 30 )
  454.             {
  455. #                DEBUGPRINT("aet_AIMophia:: Max touch count exceeded while SWOOPING");
  456.                 call FinishSwoopAttack;
  457.             }
  458.         }
  459.     }
  460.     else if ( n_eventType == 0x200 )                        #---- SITHAI_EVENTHITWALL ----
  461.     {
  462.         if ( BITTEST(n_AICstmMode, CMODE_SWOOPATTACK) )
  463.         {
  464. #            DEBUGPRINT("aet_AIMophia:: Hit wall while SWOOPING");
  465.             ReturnEx(1);
  466.             call FinishSwoopAttack;
  467.         }
  468.     }
  469.  
  470.     return;
  471.  
  472.  
  473. # ...................................................................
  474. arrivedwpnt:
  475.  
  476.     n_crntWpnt = GetParam(0);
  477.     n_nextWpnt = GetParam(1);
  478.  
  479.     #***  Retrieve current custom mode  ***#
  480.     n_AICstmMode = SendMessageEx(GetThingClassCog(t_boss), USER1, 0, 0, 0, 0);
  481.  
  482.     #***  Start Perching\Resting?  ***#
  483.     if ( (n_crntWpnt==2) || (n_crntWpnt==3) || (n_crntWpnt==4) )
  484.     {
  485.         if ( !BITTEST(n_AICstmMode, CMODE_NEEDREST) )
  486.             return;
  487.         if ( AIFindNearestWpnt(GetLocalPlayerThing()) == n_crntWpnt )
  488.             return;
  489.  
  490.         AIStopFlee(t_boss);
  491.         StopThing(t_boss);
  492.  
  493.         AISetLookThing(t_boss, t_ghostPos01);
  494.         AIWaitForStop(t_boss);
  495.  
  496.         f_val    = CheckFloorDistance(t_boss);
  497.         vec_pos = GetThingPos(t_boss);
  498.         vec_pos = VectorSet(VectorX(vec_pos), VectorY(vec_pos), VectorZ(vec_pos) - f_val);
  499.         AISetMovePos(t_boss, vec_pos, 1);
  500.  
  501.         SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_PERCH, 0, 0);
  502.         SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_HEAL, 0, 0);
  503.     }
  504.  
  505.     return;
  506.  
  507.  
  508. # ...................................................................
  509. damaged:
  510.  
  511.     if (GetSenderRef() != t_boss)
  512.         return;
  513.  
  514.     if ( BITTEST(GetParam(1), 0x800) )                                #---- SITH_DAMAGE_ELECTROWHIP
  515.     {
  516.         #***  Retrieve current custom mode  ***#
  517.         n_AICstmMode = SendMessageEx(GetThingClassCog(t_boss), USER1, 0, 0, 0, 0);
  518.  
  519.         vec_pos = VectorSub('0 0 0', GetThingLVec(t_boss));
  520.         ApplyForce(t_boss, VectorScale(vec_pos, 250));                        # Smack the boss a little
  521.  
  522.         #***  Get current Mophia size (USER4)  ***#
  523.         n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  524.  
  525.         #***  For xsml Mophia, take damage and consider death  ***#
  526.         if ( n_MophiaSize==0 )
  527.         {
  528.             num_WhipDeath    = 3 + GetDifficulty();
  529.             num_WhipHits    = num_WhipHits + 1;
  530. #           DEBUGFLEX(num_WhipHits, "Num of whip hits =");
  531.             if ( num_WhipHits >= num_WhipDeath )
  532.             {
  533.                 call TerminateSwoopAttack;
  534.                 call PrepForDeath;
  535.  
  536. #                DEBUGPRINT("aet_AIMophia:: Sending KILLED msg to cinematic cog");
  537.                 SendMessageEx(cog_cinematic, KILLED, 0, 0, 0, 0);            # Notify cinematic COG of boss death
  538.  
  539.                 AISetCutsceneMode(t_boss);
  540.                 t_boss = -1;
  541.  
  542.                 return;
  543.             }
  544.         }
  545.  
  546. #        DEBUGFLEX(GetThingHealth(t_boss), "Mophia health =");
  547.         call TerminateSwoopAttack;
  548.         call BeginRestMode;
  549.     }
  550.  
  551.     return;
  552.  
  553.  
  554. # ...................................................................
  555. timer:
  556.  
  557.     if ( GetSenderID() == TIMERID_REST )
  558.     {
  559. #        DEBUGPRINT("aet_AIMophia:: Rest TIMER elapsed");
  560.         call EndRestMode;
  561.     }
  562.  
  563.     if ( GetSenderID() == TIMERID_SWOOP )
  564.     {
  565. #        DEBUGPRINT("aet_AIMophia:: Max Swoop attack TIMER elapsed");
  566.         call FinishSwoopAttack;
  567.     }
  568.  
  569.     if ( GetSenderID() == TIMERID_ABORTSWOOP )
  570.     {
  571.         call AbortSwoopAttack;
  572.     }
  573.  
  574.     return;
  575.  
  576.  
  577. # ...................................................................
  578. pulse:
  579.  
  580.     # Retrieve current custom mode
  581.     n_AICstmMode = SendMessageEx(GetThingClassCog(t_boss), USER1, 0, 0, 0, 0);
  582.  
  583.     if ( BITTEST(n_AICstmMode, CMODE_SWOOPATTACK | CMODE_NEEDREST | CMODE_PERCH) )
  584.         return;
  585.  
  586.     AISetMoveSpeed(t_boss, 1.2);
  587.  
  588.     #***  If traversing waypoints, consider swoop attack  ***#
  589.     if ( BITTEST(AIGetMode(t_boss), 0x04000000) )
  590.     {
  591.         if ( !IsAITargetInSight(t_boss) )
  592.             return;
  593.         if ( IsModePlaying(t_boss, 65) || IsModePlaying(t_boss, 66) || IsModePlaying(t_boss, 67) )
  594.             return;
  595.  
  596.         #***  If player not on combat stage, stop sometimes  ***#
  597.         if ( !BITTEST(n_AICstmMode, CMODE_NORANGED) )
  598.         {
  599.             if ( Rand() < 0.25 )
  600.             {
  601.                 StopThing(t_boss);
  602.                 AISetLookPos(t_boss, GetThingPos(t_player));
  603.                 return;
  604.             }
  605.         }
  606.  
  607.         #***  Get current Mophia size (USER4)  ***#
  608.         n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  609.         if ( n_MophiaSize==0 )
  610.         {
  611.             #***  If mophia xsml and player not on combat stage, dont swoop attack  ***#
  612.             f_val = VectorZ( VectorSub(GetThingPos(t_player), GetThingPos(t_ghostPos00)) );
  613.             if ( f_val > 1.5 )
  614.             {
  615.                 return;
  616.             }
  617.         }
  618.  
  619.         call StartSwoopAttack;
  620.     }
  621.  
  622.     #***  Keep boss moving  ***#
  623.     n_nextWpnt    = AIFindNearestWpnt(t_boss);
  624.     AITraverseWpnts(t_boss, n_nextWpnt, 1.5, 0, 1);
  625.  
  626.     return;
  627.  
  628.  
  629. # ===================================================================
  630. #    Subroutines
  631. # ===================================================================
  632.  
  633. # ...................................................................
  634. BeginRestMode:
  635.  
  636. #    DEBUGPRINT("aet_AIMophia:: Starting rest period");
  637.  
  638.     SetPulse(0);
  639.     f_val = f_restTime;
  640.     SetTimerEx(f_val, TIMERID_REST, 0, 0);
  641.  
  642.     SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_NEEDREST, 0, 0);
  643.  
  644.     return;
  645.  
  646. # ...................................................................
  647. EndRestMode:
  648.  
  649. #    DEBUGPRINT("aet_AIMophia:: Finishing rest period");
  650.  
  651.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_NEEDREST, 0, 0);
  652.     SetPulse(RandBetween(n_minPulse, n_maxPulse));
  653.  
  654.     #***  Start boss moving  ***#
  655.     n_nextWpnt    = AIFindNearestWpnt(t_boss);
  656.     AITraverseWpnts(t_boss, n_nextWpnt, 1.5, 0, 1);
  657.  
  658.     return;
  659.  
  660.  
  661. # ...................................................................
  662. StartSwoopAttack:
  663.  
  664.     # Retrieve current custom mode
  665.     n_AICstmMode = SendMessageEx(GetThingClassCog(t_boss), USER1, 0, 0, 0, 0);
  666.  
  667.     if ( BITTEST(n_AICstmMode, CMODE_NEEDREST | CMODE_BOMBATTACK | CMODE_SWOOPATTACK) )
  668.         return;
  669.  
  670. #    DEBUGPRINT("aet_AIMophia:: Starting swoop attack");
  671.  
  672.     SetTimerEx(15, TIMERID_SWOOP, 0, 0);
  673.     n_touchCount = 0;
  674.  
  675.     Reset();
  676.     StopThing(t_boss);
  677.  
  678.     AISetLookPos(t_boss, GetThingPos(t_player));
  679.     AIWaitForStop(t_boss);
  680.  
  681.     SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_SWOOPFLIGHT, 0, 0);
  682.     SendMessageEx(GetThingClassCog(t_boss), USER0, 1, CMODE_SWOOPATTACK, 0, 0);
  683.     f_moveSize = GetThingMoveSize(t_boss);
  684.  
  685.     vec_dir    = VectorSub(GetThingPos(t_boss), GetThingPos(t_player));    # Calc a destination pos in front of player
  686.     vec_dir    = VectorSet( VectorX(vec_dir), VectorY(vec_dir), 0 );
  687.     vec_dir    = VectorNorm(vec_dir);
  688.     vec_dir = VectorScale(vec_dir, (1.2 * f_moveSize));
  689.  
  690.     vec_pos = VectorSub(GetThingPos(t_player), GetThingInsertOffset(t_player));
  691.     vec_pos = VectorAdd(vec_pos, vec_dir);
  692.     vec_pos = VectorSet(VectorX(vec_pos), VectorY(vec_pos), VectorZ(vec_pos) + (3*f_moveSize/4));
  693.  
  694.     #***  Get current Mophia size (USER4)  ***#
  695.     n_MophiaSize = SendmessageEx(GetThingClassCog(t_boss), USER4, 0, 0, 0, 0);
  696.     if ( n_MophiaSize <= 1 )
  697.     {
  698.         AISetMoveSpeed(t_boss, 2.5);
  699.     }
  700.     else
  701.     {
  702.         AISetMoveSpeed(t_boss, 4.0);
  703.     }
  704.  
  705.     snd_screech = PlaySoundClass(t_boss, 124);                                # play screech
  706.     Sleep(1.25);
  707.  
  708.     #***  If Mophia has taken damage, consider aborting mid-flight  ***#
  709.     if ( num_WhipHits > 0 )
  710.     {
  711.         f_val = 0.25 + (num_WhipHits * 0.05);
  712.         if ( Rand() <= f_val )
  713.         {
  714.             f_dist = VectorLen( VectorSub(GetThingPos(t_player), GetThingPos(t_boss)) );
  715. #            DebugFlex(f_dist, "Attack dist to player =");
  716.             if ( f_dist > 0.85 )
  717.             {
  718.                 SetTimerEx(0.8, TIMERID_ABORTSWOOP, 0, 0);
  719.             }
  720.             else
  721.             {
  722.                 SetTimerEx(0.4, TIMERID_ABORTSWOOP, 0, 0);
  723.             }
  724.         }
  725.     }
  726.  
  727.     AISetMovePos(t_boss, vec_pos, 1);
  728.  
  729. #    DEBUGPRINT("aet_AIMophia:: Swoop goal reached");
  730.     #***  Allow code to continue into FinishSwoopAttack  ***#
  731. # ...................................................................
  732. FinishSwoopAttack:
  733.  
  734.     Reset();
  735.  
  736.     KillTimerEx(TIMERID_SWOOP);
  737.     KillTimerEx(TIMERID_ABORTSWOOP);
  738.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPFLIGHT, 0, 0);
  739.  
  740.     StopThing(t_boss);
  741.     Sleep(0.5);
  742.  
  743.     vec_pos    = VectorAdd( GetThingPos(t_boss), VectorTransformToOrient(t_boss, '0.0 -0.6 0.1') );
  744.     AISetMoveSpeed(t_boss, 0.32);
  745.     AISetMovePos(t_boss, vec_pos, 0);
  746.  
  747.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPATTACK, 0, 0);
  748.  
  749.     return;
  750.  
  751.  
  752. # ...................................................................
  753. TerminateSwoopAttack:
  754.  
  755.     KillTimerEx(TIMERID_SWOOP);
  756.     KillTimerEx(TIMERID_ABORTSWOOP);
  757.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPFLIGHT, 0, 0);
  758.  
  759.     vec_pos    = VectorAdd( GetThingPos(t_boss), VectorTransformToOrient(t_boss, '0.0 -0.6 0.1') );
  760.     AISetMoveSpeed(t_boss, 0.5);
  761.     AISetMovePos(t_boss, vec_pos, 0);
  762.  
  763.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPATTACK, 0, 0);
  764.     PlayMode(t_boss, 75, 0);                                    # Play 'hit' anim manually
  765.  
  766.     return;
  767.  
  768.  
  769. # ...................................................................
  770. AbortSwoopAttack:
  771.  
  772.     KillTimerEx(TIMERID_SWOOP);
  773.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPFLIGHT, 0, 0);
  774.  
  775.     vec_pos    = VectorAdd(GetThingPos(t_player), '0.0 0.0 0.4');
  776.     AISetMovePos(t_boss, vec_pos, 1);
  777.  
  778.     SendMessageEx(GetThingClassCog(t_boss), USER0, 0, CMODE_SWOOPATTACK, 0, 0);
  779.  
  780.     return;
  781.  
  782.  
  783. # ===================================================================
  784. end
  785.  
  786.